package com.loukou.lkt.lkt.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.loukou.lkt.company.dao.UserDao;
import com.loukou.lkt.company.entity.User;
import com.loukou.lkt.lkt.bo.PageList;
import com.loukou.lkt.lkt.bo.PoPurchaseReturnOrderFinaceBo;
import com.loukou.lkt.lkt.bo.PoPurchaseReturnOrderFinaceDetailBo;
import com.loukou.lkt.lkt.bo.PoPurchaseReturnOrderFinaceListBo;
import com.loukou.lkt.lkt.bo.Query;
import com.loukou.lkt.lkt.constant.Urls;
import com.loukou.lkt.lkt.dao.GoodsCostDao;
import com.loukou.lkt.lkt.dao.GoodsDao;
import com.loukou.lkt.lkt.dao.GoodsStockDao;
import com.loukou.lkt.lkt.dao.PoPurchaseOrderDao;
import com.loukou.lkt.lkt.dao.PoPurchaseOrderDetailDao;
import com.loukou.lkt.lkt.dao.PoPurchaseReturnOrderDao;
import com.loukou.lkt.lkt.dao.PoPurchaseReturnOrderDetailDao;
import com.loukou.lkt.lkt.dao.StockOutOrderDao;
import com.loukou.lkt.lkt.dao.StockOutOrderDetailDao;
import com.loukou.lkt.lkt.dao.SupplierDao;
import com.loukou.lkt.lkt.dao.SupplierGoodsDao;
import com.loukou.lkt.lkt.dao.WarehouseDao;
import com.loukou.lkt.lkt.entity.Goods;
import com.loukou.lkt.lkt.entity.GoodsCost;
import com.loukou.lkt.lkt.entity.GoodsStock;
import com.loukou.lkt.lkt.entity.OrderOperateLog;
import com.loukou.lkt.lkt.entity.PoPurchaseOrder;
import com.loukou.lkt.lkt.entity.PoPurchaseOrderDetail;
import com.loukou.lkt.lkt.entity.PoPurchaseReturnOrder;
import com.loukou.lkt.lkt.entity.PoPurchaseReturnOrderDetail;
import com.loukou.lkt.lkt.entity.Supplier;
import com.loukou.lkt.lkt.entity.SupplierGoods;
import com.loukou.lkt.lkt.entity.Warehouse;
import com.loukou.lkt.lkt.enums.GoodsStockPositionTypeEnum;
import com.loukou.lkt.lkt.enums.GoodsStockStateEnum;
import com.loukou.lkt.lkt.enums.OrderOperateLogTypeEnum;
import com.loukou.lkt.lkt.enums.PoPurchaseReturnOrderStateEnum;
import com.loukou.lkt.lkt.enums.PoPurchaseorderStateEnum;
import com.loukou.lkt.lkt.enums.PositionTypeEnum;
import com.loukou.lkt.lkt.enums.SettlementTypeEnum;
import com.loukou.lkt.lkt.enums.StockOutOrderTypeEnum;
import com.loukou.lkt.lkt.enums.VoucherPrefixEnum;
import com.loukou.lkt.lkt.req.PoPurchaseReturnOrderGoodsDto;
import com.loukou.lkt.lkt.req.PurchaseOrderReturnReqDto;
import com.loukou.lkt.lkt.req.WmsOutOrderCallbackDetailReq;
import com.loukou.lkt.lkt.req.WmsOutOrderCallbackReq;
import com.loukou.lkt.lkt.req.WmsOutOrderNoticeDetailReq;
import com.loukou.lkt.lkt.req.WmsOutOrderNoticeReq;
import com.loukou.lkt.lkt.resp.PoPurchaseOrderLogDto;
import com.loukou.lkt.lkt.resp.PoPurchaseOrderReturnDetailRespDto;
import com.loukou.lkt.lkt.resp.RespDto;
import com.loukou.lkt.lkt.service.GoodsStockService;
import com.loukou.lkt.lkt.service.OrderOperateLogService;
import com.loukou.lkt.lkt.service.PoPurchaseReturnOrderService;
import com.loukou.lkt.lkt.service.SerialNumberService;
import com.loukou.lkt.lkt.utils.PostUtils;

@Service
public class PoPurchaseReturnOrderServiceImpl implements PoPurchaseReturnOrderService{
	@Autowired
	private PoPurchaseReturnOrderDao poReturnDao;
	@Autowired
	private PoPurchaseReturnOrderDetailDao poReturnDetailDao;
	@Autowired
	private SupplierDao supplierDao;
	@Autowired
	private SupplierGoodsDao supplierGoodsDao;
	@Autowired
	private WarehouseDao warehouseDao;
	@Autowired
	private GoodsDao goodsDao;
	@Autowired

	private GoodsStockDao goodsStockDao;
	@Autowired
	private GoodsCostDao goodsCostDao;
	@Autowired
	private UserDao userDao;

	@Autowired
	private PoPurchaseOrderDao poPurchaseorderDao;
	@Autowired
	private PoPurchaseOrderDetailDao poPurchaseOrderDetailDao;
	
	@Autowired
	private StockOutOrderDao stockOutOrderDao;
	@Autowired
	private StockOutOrderDetailDao stockOutOrderDetailDao;
	
	@Autowired
	private OrderOperateLogService orderOperateLogService;
	
	@Autowired
	private SerialNumberService serialNumberService;
	
	@Autowired
	private GoodsStockService stockService;
	
	/**
	 * 更新退货单
	 */
	@Override
	@Transactional
	public RespDto<String> updatePurchaseReturn(int stockOutOrderId,WmsOutOrderCallbackReq req) {
		RespDto<String> resp = new RespDto<String>();
		if(req == null){
			resp.setCode(401);
			resp.setMsg("参数为空");
			return resp;
		}
		
		//获取退货单
		PoPurchaseReturnOrder poPurchaseReturnOrder=poReturnDao.findByOrderReturnCode(req.getOutbizCode());
		if(poPurchaseReturnOrder == null){
			resp.setCode(402);
			resp.setMsg("退货单不存在");
			return resp;
		}
		
		//更新退货单
		poReturnDao.updatePoPurchaseReturnOrderForApi(poPurchaseReturnOrder.getId(), stockOutOrderId, req.getDeliveryTime(), PoPurchaseReturnOrderStateEnum.STATE_NOTIFIED.getState(), req.getDeliveryUserName(), req.getDeliveryTime());

		//添加出库明细
		for(WmsOutOrderCallbackDetailReq outOrderDetail:req.getDetails()){
			PoPurchaseReturnOrderDetail ppReturnOrderDetail=poReturnDetailDao.findOne(Integer.parseInt(outOrderDetail.getOutbizId()));
			if(ppReturnOrderDetail == null){
				throw new RuntimeException("采购单明细不存在");
			}
			
			//更新采购单明细
			poReturnDetailDao.updateDeliveryNumberForApi(Integer.parseInt(outOrderDetail.getOutbizId()), outOrderDetail.getDeliveryNumber());
		}
		
		OrderOperateLog savedLog = orderOperateLogService.saveOrderOperateLog(OrderOperateLogTypeEnum.TYPE_STATE_CHANGE, poPurchaseReturnOrder.getOrderReturnCode(), 0, "system", "system");
		if(null == savedLog) {
			return new RespDto<String>(500, "退货单状态操作日志失败");
		}

		resp.setMsg("更新完成");
		return resp;
	}
	
	/**
	 * 推送退货入库通知到WMS
	 */
	@Override
	public RespDto<String> sendPurchaseReturnOrderToWms(int purchaseReturnOrderId) {
		RespDto<String> resp = new RespDto<String>();
		//获取采购单
		PoPurchaseReturnOrder poPurchaseReturnOrderDto=poReturnDao.findOne(purchaseReturnOrderId);
		if(poPurchaseReturnOrderDto == null){
			resp.setCode(401);
			resp.setResult(purchaseReturnOrderId + "未找到对应退货单");
			return resp;
		}
		
		Warehouse warehouseDto=warehouseDao.findOne(poPurchaseReturnOrderDto.getWarehouseId());//获取仓库信息
		
		WmsOutOrderNoticeReq wmsOutOrderNotice = new WmsOutOrderNoticeReq();//LKT根据退货单通知WMS入库
		wmsOutOrderNotice.setOutbizCode(""+poPurchaseReturnOrderDto.getOrderReturnCode());
		wmsOutOrderNotice.setWarehouseNo(""+warehouseDto.getWarehouseCode());
		wmsOutOrderNotice.setRemark(poPurchaseReturnOrderDto.getRemark());
		wmsOutOrderNotice.setOrderType(StockOutOrderTypeEnum.TYPE_RETURN_GOODS.getType());
		
		//获取退货明细列表
		List<PoPurchaseReturnOrderDetail> poPurchaseReturnOrderDetailList = poReturnDetailDao.findByOrderId(purchaseReturnOrderId);
		if(poPurchaseReturnOrderDetailList == null || poPurchaseReturnOrderDetailList.size() == 0){
			resp.setCode(402);
			resp.setResult(purchaseReturnOrderId + "退货单明细不存在");
			return resp;
		}
		
		List<WmsOutOrderNoticeDetailReq> wmsOutOrderNoticeDetailList = new ArrayList<WmsOutOrderNoticeDetailReq>();
		for(PoPurchaseReturnOrderDetail orderDetail : poPurchaseReturnOrderDetailList){
			WmsOutOrderNoticeDetailReq outDetailReq = new WmsOutOrderNoticeDetailReq();
			outDetailReq.setOutbizId(""+orderDetail.getId());
			outDetailReq.setCustomerGoodsId(""+orderDetail.getGoodsId());
			outDetailReq.setGoodsName(orderDetail.getGoodsName());
			outDetailReq.setBarcode(orderDetail.getBn());
			outDetailReq.setQuantity(orderDetail.getOrderNumber());
			wmsOutOrderNoticeDetailList.add(outDetailReq);
		}
		wmsOutOrderNotice.setDetails(wmsOutOrderNoticeDetailList);
		PostUtils.postData(Urls.LktTellWmsInOrderNotice, wmsOutOrderNotice);
		
		//更新退货单状态为已通知
		poReturnDao.updateOrderStateById(PoPurchaseReturnOrderStateEnum.STATE_NOTIFIED.getState(),purchaseReturnOrderId);
		return resp;
	}

	@Override
	public PoPurchaseReturnOrderFinaceBo getFinaceCheckReturnOrder(int orderReturnId) {
		PoPurchaseReturnOrderFinaceBo finaceReturnBo=new PoPurchaseReturnOrderFinaceBo();		
		
		PoPurchaseReturnOrder returnOrder=poReturnDao.findById(orderReturnId);
		List<PoPurchaseReturnOrderDetail> returnOrderDetail=poReturnDetailDao.findByOrderId(orderReturnId);
		
		finaceReturnBo.setReturnOrder(returnOrder.getOrderReturnCode());
		finaceReturnBo.setSupplierName(supplierDao.findById(returnOrder.getSupplierId()).getSupplierName());
		finaceReturnBo.setWarehouse(warehouseDao.findByWarehouseId(returnOrder.getWarehouseId()).getWarehouseName());
		finaceReturnBo.setPlanReturnTime(returnOrder.getPlanReturntime());
		finaceReturnBo.setActualReturnTime(returnOrder.getActualReturntime());
		finaceReturnBo.setAddress(returnOrder.getAddress());
		finaceReturnBo.setRemark(returnOrder.getRemark());
		double returnAmount=0;
		
		List<Integer> lstGoodsIds=new ArrayList<Integer>();
		//List<Integer> lstGoodsSpecIds=new ArrayList<Integer>();
		String specIds="";
		for(PoPurchaseReturnOrderDetail rdo :returnOrderDetail){
			if(!lstGoodsIds.contains(rdo.getGoodsId())){
				lstGoodsIds.add(rdo.getGoodsId());
				/*specIds=specIds+rdo.getGoodsSpecId()+",";*/
			}			
			/*if(!lstGoodsSpecIds.contains(rdo.getGoodsSpecId())){
				lstGoodsSpecIds.add(rdo.getGoodsSpecId());
			}*/
		}
		if(specIds.endsWith(",")){
			specIds=specIds.substring(0, specIds.length()-1);
		}
		
		//商品
		List<Goods> goods=goodsDao.findByGoodsIdIn(lstGoodsIds);
		Map<Integer,Goods> goodsMap=new HashMap<Integer,Goods>();
		for(Goods g :goods){
			goodsMap.put(g.getGoodsId(), g);
		}
		
		//可用库存
		Map<Integer,GoodsStock> normalStockMap=getGoodsStockMap(returnOrder.getWarehouseId(),lstGoodsIds,
				GoodsStockPositionTypeEnum.TYPE_Normal.getId(),GoodsStockStateEnum.STATE_Normal.getId());
		//残次库存
		Map<Integer,GoodsStock> defectiveStockMap=getGoodsStockMap(returnOrder.getWarehouseId(),lstGoodsIds,
				GoodsStockPositionTypeEnum.TYPE_Abnormal.getId(),GoodsStockStateEnum.STATE_Normal.getId());
		
		//成本价
		List<GoodsCost> lstGoodsCost=goodsCostDao.getGoodsCosts(specIds);
		Map<Integer,GoodsCost> goodsCostMap=new HashMap<Integer,GoodsCost>();
		for(GoodsCost gc:lstGoodsCost){
			goodsCostMap.put(gc.getGoodsId(), gc);
		}
		
		/*//最近采购价
		Map<Integer,Double> recentPurchasePriceMap=new HashMap<Integer,Double>();
		for(int specId : lstGoodsSpecIds){
			List<PoPurchaseOrderDetail> lstPurchaseOrderDetail=poPurchaseOrderDetailDao.findByGoodsSpecId(specId);
			List<Integer> lstPurchaseOrderIds=new ArrayList<Integer>();
			Map<Integer,PoPurchaseOrderDetail> purchaseDetailMap=new HashMap<Integer,PoPurchaseOrderDetail>();			
			for(PoPurchaseOrderDetail pod :lstPurchaseOrderDetail){
				lstPurchaseOrderIds.add(pod.getOrderId());
				purchaseDetailMap.put(pod.getGoodsSpecId(), pod);
			}
			List<PoPurchaseOrder> lstPurchaseOrder=new ArrayList<PoPurchaseOrder>();
			if(!CollectionUtils.isEmpty(lstPurchaseOrderIds)){
				lstPurchaseOrder=poPurchaseorderDao.findByIdInAndOrderStateOrderByReceiveTimeDesc(lstPurchaseOrderIds, PoPurchaseorderStateEnum.STATE_RECEIVED.getState());
			}
			int purchaseOrderId=0;
			if(!CollectionUtils.isEmpty(lstPurchaseOrder)){
				purchaseOrderId=lstPurchaseOrder.get(0).getId();
			}
		}*/
		
		//最近采购价
		List<SupplierGoods> lstSupplierGoods=supplierGoodsDao.findBySupplierIdAndGoodsIdIn(returnOrder.getSupplierId(),lstGoodsIds);
		Map<Integer,SupplierGoods> supplierGoodsMap=new HashMap<Integer,SupplierGoods>();
		for(SupplierGoods sg:lstSupplierGoods){
			supplierGoodsMap.put(sg.getGoodsId(), sg);
		}
		
		List<PoPurchaseReturnOrderFinaceDetailBo> lstGoodsInfo=new ArrayList<PoPurchaseReturnOrderFinaceDetailBo>();
		for(PoPurchaseReturnOrderDetail rdo :returnOrderDetail){
			PoPurchaseReturnOrderFinaceDetailBo fdb=new PoPurchaseReturnOrderFinaceDetailBo();
			if(goodsMap.get(rdo.getGoodsId())!=null){
				fdb.setSku(goodsMap.get(rdo.getGoodsId()).getSku());
				fdb.setBarcode(goodsMap.get(rdo.getGoodsId()).getBarcode());
				fdb.setGoodsName(goodsMap.get(rdo.getGoodsId()).getGoodsName());
				fdb.setTax(goodsMap.get(rdo.getGoodsId()).getTax());
				fdb.setCarton(goodsMap.get(rdo.getGoodsId()).getPacking());
			}else{
				fdb.setSku("");
				fdb.setBarcode("");
				fdb.setGoodsName("");
				fdb.setTax(0);
				fdb.setCarton(0);
			}
			
			if(normalStockMap.get(rdo.getGoodsId())!=null){
				fdb.setStock(normalStockMap.get(rdo.getGoodsId()).getStock());
			}else{
				fdb.setStock(0);
			}
			if(defectiveStockMap.get(rdo.getGoodsId())!=null){				
				fdb.setDefectiveQuantity(defectiveStockMap.get(rdo.getGoodsId()).getStock());
			}else{				
				fdb.setDefectiveQuantity(0);
			}
			if(goodsCostMap.get(rdo.getGoodsId())!=null){
				fdb.setCostPrice(goodsCostMap.get(rdo.getGoodsId()).getCostPrice());
			}else{
				fdb.setCostPrice(0);
			}
			
			fdb.setReturnPrice(rdo.getTaxPrice());			
			fdb.setReturnQuantity(rdo.getOrderNumber());
			fdb.setReturnAmount(rdo.getTaxAmount());
			fdb.setDeliveryQuantity(rdo.getDeliveryNumber());
			
			fdb.setAverageWeeklySales(0);
			if(supplierGoodsMap.get(rdo.getGoodsId())!=null){
				fdb.setRecentPurchasePrice(supplierGoodsMap.get(rdo.getGoodsId()).getRecentPurchasePrice());
				fdb.setRecentPurchaseQuantity(supplierGoodsMap.get(rdo.getGoodsId()).getRecentPruchaseQuantity());
				fdb.setPurchaseDate(supplierGoodsMap.get(rdo.getGoodsId()).getRecentPurchaseDate());
			}else {
				fdb.setRecentPurchasePrice(0);
				fdb.setRecentPurchaseQuantity(0);
				fdb.setPurchaseDate(null);
			}
			
			
			fdb.setAdvent(new Date());
			fdb.setExpirationDate(new Date());
			
			lstGoodsInfo.add(fdb);
			returnAmount=returnAmount+rdo.getTaxAmount();
		}
		
		finaceReturnBo.setAmount(returnAmount);
		finaceReturnBo.setLstGoods(lstGoodsInfo);
		
		return finaceReturnBo;
	}
	
	Map<Integer,GoodsStock> getGoodsStockMap(int warehouseId,List<Integer> lstGoodsIds,int positionType,int stockState){
		//库存
		List<GoodsStock> goodsStock=goodsStockDao.findByWarehouseIdAndPositionTypeAndGoodsIdInAndStockState(
				warehouseId, positionType, lstGoodsIds, stockState);
		Map<Integer,GoodsStock> goodsStockMap=new HashMap<Integer,GoodsStock>();
		for(GoodsStock gss:goodsStock){
			goodsStockMap.put(gss.getGoodsId(), gss);
		}
		return goodsStockMap;
	}

	@Override
	public RespDto<PageList<PoPurchaseReturnOrderFinaceListBo>> getFinaceCheckReturnOrderList(final int orderState,
			final String returnOrder, String supplierCode, String supplierName, int purchaseType, String returnPerson,
			final Date startReturnTime, final Date endReturnTime, int pageIndex, int pageSize) {
		RespDto<PageList<PoPurchaseReturnOrderFinaceListBo>> resp=new RespDto<PageList<PoPurchaseReturnOrderFinaceListBo>>();
		PageList<PoPurchaseReturnOrderFinaceListBo> orderList=new PageList<PoPurchaseReturnOrderFinaceListBo>();
		//供应商
		final List<Integer> lstSupplierIds=new ArrayList<Integer>();
		List<Supplier> lstSupplier=new ArrayList<Supplier>();
		if(supplierCode.length()>0 && supplierName.length()<=0){
			lstSupplier=supplierDao.findBySupplierCodeLike("%"+supplierCode+"%");
		}else if(supplierCode.length()>0 && supplierName.length()>0){
			lstSupplier=supplierDao.findBySupplierCodeLikeAndSupplierNameLike("%"+supplierCode+"%", "%"+supplierName+"%");
		}else if(supplierCode.length()<=0 && supplierName.length()>0){
			lstSupplier=supplierDao.findBySupplierNameLike("%"+supplierName+"%");
		}
		
		for(Supplier su:lstSupplier){
			if(!lstSupplierIds.contains(su.getId())){
				lstSupplierIds.add(su.getId());
			}
		}		
		
		if (lstSupplierIds.size() <= 0) {
			lstSupplierIds.add(-1);
		}
		if (supplierCode.length() <= 0 && supplierName.length()<=0) {
			lstSupplierIds.clear();
		}
		
		//采购员id
		final List<Integer> lstUserIds=new ArrayList<Integer>();
		List<User> lstUsers=new ArrayList<User>();
		if(returnPerson.length()>0){
			lstUsers=userDao.findByUsernameLike(returnPerson);
		}
		for(User u:lstUsers){
			if(!lstUserIds.contains(u.getId())){
				lstUserIds.add(u.getId());
			}
		}
		
		if(lstUserIds.size()<=0){
			lstUserIds.add(-1);
		}
		if(returnPerson.length()<=0){
			lstUserIds.clear();
		}
		
		final List<Integer> lstOrderStates=new ArrayList<Integer>();
		if(orderState==0){
			lstOrderStates.add(PoPurchaseReturnOrderStateEnum.STATE_DEPART_PASS.getState());
		}else if(orderState == 1){
			lstOrderStates.add(PoPurchaseReturnOrderStateEnum.STATE_FINANCE_PASS.getState());			
		}else{
			lstOrderStates.add(PoPurchaseReturnOrderStateEnum.STATE_DEPART_PASS.getState());
			lstOrderStates.add(PoPurchaseReturnOrderStateEnum.STATE_FINANCE_PASS.getState());
			lstOrderStates.add(PoPurchaseReturnOrderStateEnum.STATE_FINANCE_UNPASS.getState());
			lstOrderStates.add(PoPurchaseReturnOrderStateEnum.STATE_SUPPLIER_RECEIVED.getState());
			lstOrderStates.add(PoPurchaseReturnOrderStateEnum.STATE_CLOSED.getState());
			lstOrderStates.add(PoPurchaseReturnOrderStateEnum.STATE_CANCELED.getState());
		}
		
		Page<PoPurchaseReturnOrder> pageReturnOrder=poReturnDao.findAll(new Specification<PoPurchaseReturnOrder>() {
			@Override
			public Predicate toPredicate(Root<PoPurchaseReturnOrder> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				Query<PoPurchaseReturnOrder> q = new Query<PoPurchaseReturnOrder>(cb, root, query);
				q.like("orderReturnCode", returnOrder);
				//q.between("orderState", startOrderState, endOrderState);
				if(!CollectionUtils.isEmpty(lstOrderStates)){
					q.in("orderState", lstOrderStates);
				}
				if (!CollectionUtils.isEmpty(lstSupplierIds)) {
					q.in("supplierId", lstSupplierIds);
				}
				if(!CollectionUtils.isEmpty(lstUserIds)){
					q.in("userId", lstUserIds);
				}
				q.betweens("planReturntime", startReturnTime, endReturnTime);
				return q.toPredicate();
			}
		}, new PageRequest(pageIndex - 1, pageSize,Sort.Direction.DESC, "planReturntime"));
		
		List<Integer> searchedSupplierIds=new ArrayList<Integer>();
		List<Integer> searchedUserIds=new ArrayList<Integer>();
		for(PoPurchaseReturnOrder por :pageReturnOrder){
			if(!searchedSupplierIds.contains(por.getSupplierId())){
				searchedSupplierIds.add(por.getSupplierId());
			}
			if(!searchedUserIds.contains(por.getUserId())){
				searchedUserIds.add(por.getUserId());
			}
		}
		
		//供应商
		Map<Integer,Supplier> supplierMap=new HashMap<Integer,Supplier>();
		if(!CollectionUtils.isEmpty(searchedSupplierIds)){
			List<Supplier> lstSuppliers=supplierDao.findByIdIn(searchedSupplierIds);
			for(Supplier su:lstSuppliers){
				supplierMap.put(su.getId(), su);
			}
		}
		
		//采购人
		Map<Integer,User> userMap=new HashMap<Integer,User>();
		if(!CollectionUtils.isEmpty(searchedUserIds)){
			List<User> lstUser=userDao.findByIdIn(searchedUserIds);
			for(User u:lstUser){
				userMap.put(u.getId(), u);
			}
		}
		
		if(pageReturnOrder !=null && pageReturnOrder.getSize()>0){
			List<PoPurchaseReturnOrderFinaceListBo> orderListBo=orderList.getEntityList();
			for(PoPurchaseReturnOrder por :pageReturnOrder){
				PoPurchaseReturnOrderFinaceListBo bo=new PoPurchaseReturnOrderFinaceListBo();
				bo.setOrderId(por.getId());
				bo.setReturnOrder(por.getOrderReturnCode());
				//审核状态
				if(por.getOrderState()>=PoPurchaseReturnOrderStateEnum.STATE_DEPART_PASS.getState()){
					bo.setCheckedState(PoPurchaseReturnOrderStateEnum.STATE_DEPART_PASS.getName());
				}else{
					bo.setCheckedState("未审核");
				}
				//财务审核状态
				if(por.getOrderState() == PoPurchaseReturnOrderStateEnum.STATE_FINANCE_PASS.getState()){
					bo.setFinaceCheckedState(PoPurchaseReturnOrderStateEnum.STATE_FINANCE_PASS.getName());
				}else if(por.getOrderState() == PoPurchaseReturnOrderStateEnum.STATE_FINANCE_UNPASS.getState()){
					bo.setFinaceCheckedState(PoPurchaseReturnOrderStateEnum.STATE_FINANCE_UNPASS.getName());
				}
				else{
					bo.setFinaceCheckedState("未审核");
				}
				bo.setOrderState(por.getOrderState());
				bo.setPurchaseType("采购退货");
				if(supplierMap.get(por.getSupplierId())!=null){
					bo.setSupplierCode(supplierMap.get(por.getSupplierId()).getSupplierCode());
					bo.setSupplierName(supplierMap.get(por.getSupplierId()).getSupplierName());
					bo.setSettmentType(SettlementTypeEnum.parseSettlementTypeEnum(supplierMap.get(por.getSupplierId()).getSettmentType()).getName());
				}else{
					bo.setSupplierCode("");
					bo.setSupplierName("");
					bo.setSettmentType("");
				}
				bo.setReturnDate(por.getPlanReturntime());
				if(userMap.get(por.getUserId())!=null){
					bo.setReturnPerson(userMap.get(por.getUserId()).getUsername());
				}else{
					bo.setReturnPerson("");
				}
				
				List<PoPurchaseReturnOrderDetail> returnOrderDetail=poReturnDetailDao.findByOrderId(por.getId());
				double number=0;
				double amount=0;
				double actualNumber=0;
				for(PoPurchaseReturnOrderDetail pord:returnOrderDetail){
					number=number+pord.getOrderNumber();
					amount=amount+pord.getTaxAmount();
					actualNumber=actualNumber+pord.getDeliveryNumber();
				}
				
				bo.setReturnNumber(number);
				bo.setReturnAmount(amount);
				bo.setActualDeliveryNumber(actualNumber);
				
				orderListBo.add(bo);
			}
			
			orderList.setCurPageIndex(pageIndex);
			orderList.setPageCount(pageReturnOrder.getTotalPages());
			orderList.setRecordCount(pageReturnOrder.getTotalElements());
		}
		
		resp.setResult(orderList);
		
		return resp;
	}

	@Override
	public RespDto<String> finaceAuditReturnOrder(int orderReturnId,int userId) {
		RespDto<String> res=new RespDto<String>();
		res.setCode(200);
		res.setMsg("财务审核成功");
		
		PoPurchaseReturnOrder returnOrder=poReturnDao.findById(orderReturnId);
		if(returnOrder !=null &&  returnOrder.getOrderState() ==PoPurchaseReturnOrderStateEnum.STATE_DEPART_PASS.getState()){
			returnOrder.setOrderState(PoPurchaseReturnOrderStateEnum.STATE_FINANCE_PASS.getState());
			returnOrder.setFinaceCheckUserId(userId);
			returnOrder.setFinaceCheckTime(new Date());
			poReturnDao.save(returnOrder);
			
		}else{
			res.setCode(201);
			res.setMsg("单据状态不对，不能做财务审核动作！");
		}	
		return res;
	}

	@Override
	public RespDto<String> finaceRejectReturnOrder(int orderReturnId, int userId) {
		RespDto<String> res=new RespDto<String>();
		res.setCode(200);
		res.setMsg("财务否决成功");
		
		PoPurchaseReturnOrder returnOrder=poReturnDao.findById(orderReturnId);
		if(returnOrder !=null && returnOrder.getOrderState() ==PoPurchaseReturnOrderStateEnum.STATE_DEPART_PASS.getState()){
			returnOrder.setOrderState(PoPurchaseReturnOrderStateEnum.STATE_FINANCE_UNPASS.getState());
			returnOrder.setFinaceCheckUserId(userId);
			returnOrder.setFinaceCheckTime(new Date());			
			poReturnDao.save(returnOrder);
			
		}else{
			res.setCode(201);
			res.setMsg("单据状态不对，不能做财务否决动作！");
		}
		return res;
	}

	@Override
	@Transactional
	public RespDto<String> submitReturnOrder(PurchaseOrderReturnReqDto req) {
		
		if(null == req) {
			return new RespDto<String>(400, "参数有误");
		}
		
		PoPurchaseReturnOrder returnOrder = new PoPurchaseReturnOrder();
		
		fillReturnOrder(returnOrder, req);
		PoPurchaseReturnOrder savedReturnOrder = poReturnDao.save(returnOrder);
		
		if(null == savedReturnOrder) {
			return new RespDto<String>(400, "保存退货单失败");
		}
		
		List<PoPurchaseReturnOrderDetail> returnOrderDetails = new ArrayList<PoPurchaseReturnOrderDetail>();
		
		List<PoPurchaseReturnOrderGoodsDto> reqDtoList = req.getDetails();
		
		fillReturnOrderDetail(returnOrderDetails, reqDtoList, savedReturnOrder.getId(), req.getWarehouseId());
		
		List<PoPurchaseReturnOrderDetail> savedReturnOrderDetails = (List<PoPurchaseReturnOrderDetail>) poReturnDetailDao.save(returnOrderDetails);
		
		if(CollectionUtils.isEmpty(savedReturnOrderDetails)) {
			return new RespDto<String>(400, "保存退货单详情失败");
		}
		
		User user = userDao.findOne(req.getUserId());
		
		orderOperateLogService.saveOrderOperateLog(OrderOperateLogTypeEnum.TYPE_NEW, 
				savedReturnOrder.getOrderReturnCode(), req.getUserId(), 
				user.getUsername(), user.getRealName());

		return new RespDto<String>(200, "");
	}

	private void fillReturnOrderDetail(
			List<PoPurchaseReturnOrderDetail> returnOrderDetails,
			List<PoPurchaseReturnOrderGoodsDto> reqDtoList,
			int orderId, int warehouseId) {
		if(CollectionUtils.isEmpty(reqDtoList)) {
			return;
		}
		
		for(PoPurchaseReturnOrderGoodsDto dto : reqDtoList) {
			PoPurchaseReturnOrderDetail detail = new PoPurchaseReturnOrderDetail();
			detail.setOrderId(orderId);
			detail.setGoodsId(dto.getGoodsId());
			/*detail.setGoodsSpecId(dto.getGoodsSpecId());*/
//			detail.setIsGift(dto.getIsGift());
			detail.setTaxPrice(dto.getReturnPrice());
			detail.setOrderNumber(dto.getReturnNum());
			
			//更新库存
		    updateStock(dto.getReturnNum(), 0, warehouseId, dto.getGoodsSpecId());
			
			detail.setTaxAmount(dto.getReturnPrice() * dto.getReturnNum());
			detail.setTaosku(dto.getTaosku());
			detail.setBn(dto.getBn());
			detail.setGoodsName(dto.getGoodsName());
			returnOrderDetails.add(detail);
		}
		
	}

	private void fillReturnOrder(PoPurchaseReturnOrder returnOrder,
			PurchaseOrderReturnReqDto req) {
		
		String orderReturnCode = serialNumberService.generateNewVoucherCode(
				VoucherPrefixEnum.PREFIX_RETURN_ORDER, req.getWarehouseId());
		
		returnOrder.setOrderReturnCode(orderReturnCode);
		returnOrder.setSupplierId(req.getSupplierId());
		returnOrder.setUserId(req.getUserId());
		returnOrder.setWarehouseId(req.getWarehouseId());
		returnOrder.setPlanReturntime(req.getPlanReturntime());
		returnOrder.setOrderState(PoPurchaseReturnOrderStateEnum.STATE_NEW.getState());
		returnOrder.setReason(req.getReason());
		returnOrder.setRemark(req.getRemark());
		returnOrder.setAddress(req.getAddress());
		
	}

	@Override
	public PoPurchaseOrderReturnDetailRespDto getReturnOrderDetail(
			String orderCode) {
		if(StringUtils.isBlank(orderCode)) {
			return new PoPurchaseOrderReturnDetailRespDto();
		}
		// order, detail, log
		PoPurchaseReturnOrder returnOrder = poReturnDao.findByOrderReturnCode(orderCode);
		if(null == returnOrder) {
			return new PoPurchaseOrderReturnDetailRespDto();
		}
		PoPurchaseOrderReturnDetailRespDto respDto = new PoPurchaseOrderReturnDetailRespDto();
		respDto.setOrderId(returnOrder.getId());
		respDto.setOrderCode(returnOrder.getOrderReturnCode());
		respDto.setSupplierId(returnOrder.getSupplierId());
		Supplier supplier = supplierDao.findOne(returnOrder.getSupplierId());
		respDto.setSupplierName(supplier.getSupplierName());
		respDto.setWarehouseId(returnOrder.getWarehouseId());
		String warehouseName = warehouseDao.findOne(returnOrder.getWarehouseId()).getWarehouseName();
		respDto.setWarehouseName(warehouseName);
		respDto.setPlanReturntime(returnOrder.getPlanReturntime());
		if(returnOrder.getOrderState() == PoPurchaseReturnOrderStateEnum.STATE_CLOSED.getState()) {
			respDto.setActualReturntime(returnOrder.getActualReturntime());
		}
		respDto.setReason(returnOrder.getReason());
		respDto.setRemark(returnOrder.getRemark());
		respDto.setAddress(returnOrder.getAddress());
		
		List<PoPurchaseReturnOrderDetail> returnOrderList = poReturnDetailDao.findByOrderId(returnOrder.getId());
		List<com.loukou.lkt.lkt.resp.PoPurchaseReturnOrderGoodsDto> returnOrderGoods = new ArrayList<com.loukou.lkt.lkt.resp.PoPurchaseReturnOrderGoodsDto>();
		
		respDto.setReturnOrderGoods(returnOrderGoods);
		
		List<Integer> goodsIds = new ArrayList<Integer>();
		List<Integer> specIds = new ArrayList<Integer>();
		for(PoPurchaseReturnOrderDetail d : returnOrderList) {
			goodsIds.add(d.getGoodsId());
			/*specIds.add(d.getGoodsSpecId());*/
		}
		//goodsId->tax, specid->
		List<Goods> goodsList = (List<Goods>) goodsDao.findAll(goodsIds);
		/*List<GoodsSpec> specList = (List<GoodsSpec>) goodsSpecDao.findAll(specIds);*/
		
		//残次库存
		Map<Integer,GoodsStock> defectiveStockMap=getGoodsStockMap(returnOrder.getWarehouseId(), goodsIds,
						GoodsStockPositionTypeEnum.TYPE_Abnormal.getId(),GoodsStockStateEnum.STATE_Normal.getId());
		
		Map<Integer, Integer> goodsIdAvaliableStockMap = caculateAvaliableGoodsNum(goodsIds, returnOrder.getWarehouseId());
		
		for(PoPurchaseReturnOrderDetail d : returnOrderList) {
			com.loukou.lkt.lkt.resp.PoPurchaseReturnOrderGoodsDto dto = new com.loukou.lkt.lkt.resp.PoPurchaseReturnOrderGoodsDto();
			dto.setBn(d.getBn());
			dto.setGoodsId(d.getGoodsId());
			dto.setTaosku(d.getTaosku());
			dto.setReturnPrice(d.getTaxPrice());
			dto.setReturnNum(d.getDeliveryNumber());
			/*dto.setGoodsSpecId(d.getGoodsSpecId());*/
			for(Goods g : goodsList) {
				if(g.getGoodsId() == d.getGoodsId()) {
					dto.setTaxRate(g.getTax());
					dto.setGoodsName(g.getGoodsName());
					dto.setPackageSpec(g.getPacking());
				}
			}
			dto.setGoodsAmount(d.getTaxPrice() * d.getDeliveryNumber());
			
			/*for(GoodsSpec gs : specList) {
				if(gs.getSpecId() == d.getGoodsSpecId()) {
					dto.setPackageSpec(gs.getPacking());
				}
			}*/
			dto.setCostPrice(goodsCostDao.getGoodsCost(d.getGoodsId()).getCostPrice());;
			for(Map.Entry<Integer,GoodsStock> entry : defectiveStockMap.entrySet()) {
				if(entry.getKey() == d.getGoodsId()) {
					dto.setDefectiveNum(entry.getValue().getStock());
				}
 			}
			
			for(Map.Entry<Integer, Integer> entry : goodsIdAvaliableStockMap.entrySet()) {
				if(entry.getKey() == d.getGoodsId()) {
					dto.setAvaliableNum(entry.getValue());
				}
			}
			dto.setPurchasePrice(0);//TODO 确定是否仓库供应商最近采购价
			returnOrderGoods.add(dto);
		}
		
		//fill loglist
		
		List<OrderOperateLog> logList = orderOperateLogService.findByOrderCode(orderCode);
		List<PoPurchaseOrderLogDto> logDtoList = new ArrayList<PoPurchaseOrderLogDto>();
		
		for(OrderOperateLog l : logList) {
			PoPurchaseOrderLogDto dto = new PoPurchaseOrderLogDto();
			dto.setAction(l.getAction());
			dto.setCreateTime(l.getCreateTime());
			dto.setRealName(l.getRealName());
			dto.setUserId(l.getId());
			dto.setUserName(l.getUserName());
			logDtoList.add(dto);
		}
		respDto.setLog(logDtoList);
		return respDto;
	}
	
	/**
	 * FIXME 可用库存的计算方法
	 * @param goodsIds
	 * @param warehouseId
	 * @return
	 */
	private Map<Integer, Integer> caculateAvaliableGoodsNum(List<Integer> goodsIds, int warehouseId) {
		
		//获取商品库存
		List<GoodsStock> goodsStockList = goodsStockDao.findByWarehouseIdAndPositionTypeAndStockStateAndGoodsIdIn(
						warehouseId, PositionTypeEnum.TYPE_Normal.getId(), 
						GoodsStockStateEnum.STATE_Normal.getId(), goodsIds);
		Map<Integer, Integer> goodsIdAvaliableStockMap = new HashMap<Integer, Integer>();
		for(GoodsStock gs : goodsStockList) {
			goodsIdAvaliableStockMap.put(gs.getGoodsId(), gs.getStock());
		}
		return goodsIdAvaliableStockMap;
	}

	@Transactional
	@Override
	public RespDto<String> editReturnOrder(PurchaseOrderReturnReqDto req) {
		int row = poReturnDao.updatePoPurchaseReturnOrderForEdit(req.getReturnOrderId(), 
				req.getWarehouseId(), req.getPlanReturntime(), 
				req.getActualArrivetime(), req.getReason(), req.getAddress(), req.getRemark());
		if(row < 1) {
			return new RespDto<String>(401, "更新退货单失败");
		}
		
		User user = userDao.findOne(req.getUserId());
		orderOperateLogService.saveOrderOperateLog(OrderOperateLogTypeEnum.TYPE_EDIT, 
				req.getReturnOrderCode(), req.getUserId(), user.getUsername(), user.getRealName());
		
		List<PoPurchaseReturnOrderGoodsDto> details = req.getDetails();
		List<PoPurchaseReturnOrderDetail> detailList = poReturnDetailDao.findByOrderId(req.getReturnOrderId());
		
		for(PoPurchaseReturnOrderGoodsDto dto : details) {
			for(PoPurchaseReturnOrderDetail d : detailList) {
				if(d.getGoodsId() == dto.getGoodsId()) {
					
					updateStock(dto.getReturnNum(), d.getOrderNumber(), req.getWarehouseId(), dto.getGoodsSpecId());
					
					poReturnDetailDao.updateForEdit(dto.getReturnPrice(), dto.getReturnNum(), dto.getGoodsSpecId());
				}
			}
			
			PoPurchaseReturnOrderDetail orderDetail = new PoPurchaseReturnOrderDetail();
			orderDetail.setTaxPrice(dto.getReturnPrice());
			orderDetail.setOrderNumber(dto.getReturnNum());
			detailList.add(orderDetail);
		}
		
		return new RespDto<String>(200, "");
	}
	
	//更新库存及冻结库存
	@Transactional
	private void updateStock(int newNum, int oldNum, int warehouseId, int goodsId) {
		
		GoodsStock goodsStock = goodsStockDao.findByWarehouseIdAndPositionTypeAndGoodsIdAndStockState(
				warehouseId, PositionTypeEnum.TYPE_Normal.getId(), 
				goodsId, GoodsStockStateEnum.STATE_AllocationStay.getId());
		/*GoodsSpec goodsSpec = goodsSpecDao.findOne(specId);*/
		if(null == goodsStock) {
			GoodsStock gs = new GoodsStock();
			gs.setCreateTime(new Date());
			gs.setGoodsId(goodsId);
			/*gs.setGoodsSpecId(specId);*/
			gs.setPositionType(PositionTypeEnum.TYPE_Normal.getId());
			gs.setStock(newNum);
			gs.setStockState(GoodsStockStateEnum.STATE_AllocationStay.getId());
			gs.setWarehouseId(warehouseId);
			goodsStockDao.save(gs);
		}
		
		if(newNum > oldNum) {
			int diffNum = newNum - oldNum;
			//更新冻结库存
			goodsStockDao.plusStock(diffNum, goodsStock.getId());
			//更新goodsStock
			goodsStockDao.minusStock(warehouseId, PositionTypeEnum.TYPE_Normal.getId(), 
					GoodsStockStateEnum.STATE_Normal.getId(), goodsId, diffNum);
		} else {
			int diffNum = newNum - oldNum;
			//更新冻结库存
			goodsStockDao.minusStock(diffNum, goodsStock.getId());
			//更新goodsStock
			goodsStockDao.plusStock(warehouseId, PositionTypeEnum.TYPE_Normal.getId(), 
					GoodsStockStateEnum.STATE_Normal.getId(), goodsId, diffNum);
		}
	}	
	
	

	@Override
	public PoPurchaseOrderReturnDetailRespDto getReturnOrderInit(
			int warehouseId, int supplierId) {
		List<Integer> states = new ArrayList<Integer>();
		states.add(PoPurchaseorderStateEnum.STATE_RECEIVED.getState());
		states.add(PoPurchaseorderStateEnum.STATE_CLOSED.getState());
		List<PoPurchaseOrder> orderList = poPurchaseorderDao.findBySupplierIdAndWarehouseIdAndOrderStateIn(supplierId, warehouseId, states);
		
		if(CollectionUtils.isEmpty(orderList)) {
			return new PoPurchaseOrderReturnDetailRespDto();
		}
		
		List<Integer> detailIds = new ArrayList<Integer>();
		for(PoPurchaseOrder o : orderList) {
			detailIds.add(o.getId());
		}
		
		Supplier supplier = supplierDao.findById(supplierId);
		
		List<PoPurchaseOrderDetail> details = poPurchaseOrderDetailDao.findByOrderIdIn(detailIds);
		
		PoPurchaseOrderReturnDetailRespDto respDto = new PoPurchaseOrderReturnDetailRespDto();
		List<com.loukou.lkt.lkt.resp.PoPurchaseReturnOrderGoodsDto> returnOrderGoods = 
				new ArrayList<com.loukou.lkt.lkt.resp.PoPurchaseReturnOrderGoodsDto>();
		
		respDto.setSupplierName(supplier.getSupplierName());
		respDto.setWarehouseId(warehouseId);
		
		List<Integer> goodsIds = new ArrayList<Integer>();
		List<Integer> specIds = new ArrayList<Integer>();
		for(PoPurchaseOrderDetail d : details) {
			goodsIds.add(d.getGoodsId());
			/*specIds.add(d.getGoodsSpecId());*/
		}
		
		List<Goods> goodsList = (List<Goods>) goodsDao.findAll(goodsIds);
		/*List<GoodsSpec> specList = (List<GoodsSpec>) goodsSpecDao.findAll(specIds);*/
		
		//残次库存
//		Map<Integer,GoodsStock> defectiveStockMap=getGoodsStockMap(warehouseId, specIds,
//						GoodsStockPositionTypeEnum.TYPE_Abnormal.getId(),GoodsStockStateEnum.STATE_Normal.getId());
		
		Map<Integer, Integer> goodsIdAvaliableStockMap = caculateAvaliableGoodsNum(goodsIds, warehouseId);
		for(PoPurchaseOrderDetail d : details) {
			com.loukou.lkt.lkt.resp.PoPurchaseReturnOrderGoodsDto dto = new com.loukou.lkt.lkt.resp.PoPurchaseReturnOrderGoodsDto();
			dto.setTaosku(d.getTaosku());
			dto.setBn(d.getBn());
			dto.setGoodsName(d.getGoodsName());
			dto.setGoodsId(d.getGoodsId());
			/*dto.setGoodsSpecId(d.getGoodsSpecId());*/
			for(Goods g : goodsList) {
				if(g.getGoodsId() == d.getGoodsId()) {
					dto.setTaxRate(g.getTax());
					dto.setPackageSpec(g.getPacking());
				}
			}
			dto.setRecentPurchasePrice(caculateRecentSupplierPrice(d.getGoodsId(), supplierId));
			for(Map.Entry<Integer, Integer> entry : goodsIdAvaliableStockMap.entrySet()) {
				if(entry.getKey() == d.getGoodsId()) {
					dto.setAvaliableNum(entry.getValue());
				}
			}
			dto.setPerWeekSaleNum(0);//mock
			double costPrice = goodsCostDao.getGoodsCost(d.getGoodsId()).getCostPrice();
			dto.setCostPrice(costPrice);
			
			/*for(GoodsSpec gs : specList) {
				if(gs.getSpecId() == d.getGoodsSpecId()) {
					dto.setPackageSpec(gs.getPacking());
				}
			}*/
			
			returnOrderGoods.add(dto);
		}
		respDto.setReturnOrderGoods(returnOrderGoods);
		return respDto;
	}
	
	
	/**
	 *TODO
	 * @param specId
	 * @param supplierId
	 * @return 供应商范围最近一次采购价（必须已到货）
	 */
	private double caculateRecentSupplierPrice(int specId, int supplierId) {
		
		return 0;
	}
}
